package cn.lf.utils;

import cn.lf.config.MinioInitialization;
import cn.lf.constant.MinioConstants;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import io.minio.messages.Tags;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author guoyy
 */
@Slf4j
public class MinioEnhance {

    /**
     * 复制文件
     * @param targetName 目标文件  要复制到的位置
     * @param objectName 复制文件  被复制的文件
     * @return
     */
    public static boolean copyObject(String targetName,String objectName){
        try {
            MinioInitialization.getClient().copyObject(
                    CopyObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(targetName)
                            .source(CopySource.builder()
                                    .bucket(MinioConstants.MINIO_BUCKET_NAME)
                                    .object(objectName)
                                    .build())
                            .build()
            );
        } catch (Exception e) {

            e.printStackTrace();

            log.error("Minio文件复制失败："+e.getMessage());

            return false;

        }

        return true;
    }

    /**
     * 合并Minio文件
     * @param sourceArrayList
     * @param objectName
     * @return
     */
    public static boolean composeObject(List<ComposeSource> sourceArrayList,String objectName){

        try {

            MinioInitialization.getClient().composeObject(
                    ComposeObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .sources(sourceArrayList)
                            .build()
            );

        } catch (Exception e) {

            e.printStackTrace();

            log.error("Minio文件合并失败："+e.getMessage());

            return false;

        }

        return true;
    }

    /**
     * 列出指定前缀的文件
     * @param prefix
     * @return
     */
    public static Iterable<Result<Item>> listObjects(String prefix){

        Iterable<Result<Item>> results = null;

        try {

            results = MinioInitialization.getClient().listObjects(
                    ListObjectsArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .prefix(prefix)
                            .build()
            );

        }catch (Exception e) {

            e.printStackTrace();

            log.error("Minio列出指定前缀的文件失败："+e.getMessage());

        }

        return results;

    }

    /**
     * 列出指定前缀和结尾的文件  默认数量1000
     * @param prefix 前缀
     * @param startAfter 结尾
     * @return
     */
    public static Iterable<Result<Item>> listObjects(String prefix,String startAfter){

        Iterable<Result<Item>> results = null;

        try {

            results = MinioInitialization.getClient().listObjects(
                    ListObjectsArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .prefix(prefix)
                            .startAfter(startAfter)
                            .build()
            );

        }catch (Exception e) {

            e.printStackTrace();

            log.error("Minio列出指定前缀和结尾的文件失败："+e.getMessage());

        }

        return results;

    }

    /**
     * 文件上传------multipart(自定义分块大小)
     * @param objectName
     * @param file
     * @param objectSize
     * @param partSize
     * @return
     */
    public static boolean putObject(String objectName, MultipartFile file,long objectSize,long partSize){

        try {

            MinioInitialization.getClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .stream(file.getInputStream(),objectSize,partSize)
                            .build()
            );

        }catch (Exception e) {

            e.printStackTrace();

            log.error("Minio文件上传失败："+e.getMessage());

            return false;

        }

        return true;

    }

    /**
     * 文件上传------multipart(不限制分块大小)
     * @param objectName
     * @param file
     * @return
     */
    public static boolean putObject(String objectName, MultipartFile file){
        try {

            MinioInitialization.getClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .stream(file.getInputStream(),-1,10485760)
                            .build()
            );

        }catch (Exception e) {

            log.error("Minio文件上传失败："+e.getMessage());

            return false;

        }

        return true;
    }

    /**
     * 文件上传------流(自定义分块大小)
     * @param objectName
     * @param in
     * @param objectSize
     * @param partSize
     * @return
     */
    public static boolean putObject(String objectName, InputStream in,long objectSize,long partSize){

        try {

            MinioInitialization.getClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .stream(in,objectSize,partSize)
                            .build()
            );

        }catch (Exception e) {

            e.printStackTrace();

            log.error("Minio文件上传失败："+e.getMessage());

            return false;

        }

        return true;

    }

    /**
     * 文件上传------流(不限制分块大小)
     * @param objectName
     * @param in
     * @return
     */
    public static boolean putObject(String objectName, InputStream in){
        try {

            MinioInitialization.getClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .stream(in,-1,10485760)
                            .build()
            );

        }catch (Exception e) {

            e.printStackTrace();

            log.error("Minio文件上传失败："+e.getMessage());

            return false;

        }

        return true;
    }

    /**
     * 获取对象的下载url
     * @param objectName
     * @return
     */
    public static String getObjectUrl(String objectName){

        String url = null;

        try {

            url = MinioInitialization.getClient().getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .method(Method.GET)
                            .build()
            );

        }catch (Exception e) {

            log.error(e.getMessage());

        }

        return url;

    }

    /**
     * 获取对象的下载url
     * @param objectName
     * @param expires 过期时间
     * @return
     */
    public static String getObjectUrl(String objectName,Integer expires){

        String url = null;

        try {

            url = MinioInitialization.getClient().getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .expiry(expires)
                            .build()
            );

        }catch (Exception e) {

            log.error(e.getMessage());

        }

        return url;

    }

    /**
     * 判断文件是否存在
     * @param objectName
     * @return
     */
    public static boolean statObject(String objectName){

        try {

            MinioInitialization.getClient().statObject(
                    StatObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .build()
            );

            return true;

        }catch (Exception e) {

            log.error("文件不存在:"+e.getMessage());

            return false;

        }


    }

    /**
     * 删除文件 删除操作需要业务层调用迭代器
     * @param list
     * @return
     */
    public static List<String> removeObjects(List<DeleteObject> list){

        List<String> errorList = new ArrayList<>();

        try {

            Iterable<Result<DeleteError>> results = MinioInitialization.getClient().removeObjects(
                    RemoveObjectsArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .objects(list)
                            .build()
            );

            for (Result<DeleteError> result : results) {

                DeleteError deleteError = result.get();

                log.error("Minio删除文件失败：对象名称：{}，错误信息：{}",deleteError.objectName(),deleteError.message());

                errorList.add(deleteError.objectName());

            }

        }catch (Exception e){

            log.error("Minio删除文件失败"+e.getMessage());

            e.printStackTrace();

        }

        return errorList;

    }

    /**
     * 删除单个文件
     * @param objectName
     * @return
     */
    public static boolean removeObject(String objectName){

        try {

            MinioInitialization.getClient().removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .build()
            );

        }catch (Exception e){

            log.error("Minio删除单个文件失败"+e.getMessage());

            return false;
        }

        return true;

    }

    /**
     * 获取对象标签
     * @param objectName
     * @return
     */
    public static Tags getObjectTags(String objectName){

        Tags tags = null;

        try {

            tags = MinioInitialization.getClient().getObjectTags(
                    GetObjectTagsArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .build()
            );

        }catch (Exception e){

            log.error("Minio获取对象标签失败"+e.getMessage());

        }

        return tags;

    }

    /**
     * 根据文件名称获取流
     * @param objectName
     * @return
     */
    public static InputStream getObject(String objectName){

        InputStream inputStream = null;

        try {

            inputStream = MinioInitialization.getClient().getObject(
                    GetObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .build()
            );

        }catch (Exception e){

            log.error("Minio根据文件名称获取流失败"+e.getMessage());

        }

        return inputStream;
    }

    /**
     * 下载文件到指定路径
     * @param objectName
     * @param path
     */
    public static void downObjectToPath(String objectName,String path){

        try {

            MinioInitialization.getClient().downloadObject(
                    DownloadObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .filename(path)
                            .build()
            );

        }catch (Exception e){

            log.error("Minio下载文件到指定路径失败"+e.getMessage());

        }

    }

    /**
     *
     * @param objectName
     * @return
     */
    public static GetObjectResponse getObjectResponse(String objectName){

        GetObjectResponse result = null;

        try {

            result = MinioInitialization.getClient().getObject(
                    GetObjectArgs.builder()
                            .bucket(MinioConstants.MINIO_BUCKET_NAME)
                            .object(objectName)
                            .build()
            );

        }catch (Exception e){

            log.error(e.getMessage());

        }

        return result;
    }


}
